/*
*
* ████████╗░█████╗░███████╗██████╗░░█████╗░
* ╚══██╔══╝██╔══██╗██╔════╝██╔══██╗██╔══██╗
* ░░░██║░░░██║░░██║█████╗░░██████╦╝███████║
* ░░░██║░░░██║░░██║██╔══╝░░██╔══██╗██╔══██║
* ░░░██║░░░╚█████╔╝██║░░░░░██████╦╝██║░░██║
* ░░░╚═╝░░░░╚════╝░╚═╝░░░░░╚═════╝░╚═╝░░╚═╝
* 
*  :: 九方通逊-Henry ::   Copyright©2020 tofba.com  
* 
*/
package com.lmexpress.service.impl;

import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.lmexpress.enums.ApiCredential;
import com.lmexpress.enums.ApiOrderError;
import com.lmexpress.enums.LabelFormat;
import com.lmexpress.enums.LabelSuffix;
import com.lmexpress.orm.openapi.ExpressOrderApi;
import com.lmexpress.orm.openapi.OrderInvoice;
import com.lmexpress.orm.openapi.OrderVolume;
import com.lmexpress.orm.postpony.CustomsItem;
import com.lmexpress.orm.postpony.DownloadRequest;
import com.lmexpress.orm.postpony.Package;
import com.lmexpress.orm.postpony.PackageItemInfo;
import com.lmexpress.orm.postpony.Recipient;
import com.lmexpress.orm.postpony.RequstInfo;
import com.lmexpress.orm.postpony.ShipRequest;
import com.lmexpress.orm.postpony.Shipper;
import com.lmexpress.orm.postpony.UserCredential;
import com.lmexpress.orm.rest.ApiLabelResponse;
import com.lmexpress.orm.rest.ApiOrderResponse;
import com.lmexpress.service.ApiService;
import com.lmexpress.util.ApiUtil;
import com.lmexpress.util.CountryUtil;
import com.lmexpress.util.HttpClientPoolUtil;
import com.lmexpress.util.HttpClientResult;
import com.lmexpress.util.PropertiesUtil;

/**
 * <邮差小马>
 * 
 * @author Henry(fba02)
 * @version [版本号, 2020-12-09]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
public class PostPonyClient implements ApiService {
    private final static Logger LOGGER = LoggerFactory.getLogger(PostPonyClient.class);
    private final static String FAIL = "false";
    private final static String ENABLE = "1";
    private final static String LAX = "LAX";
    private final static String JFK = "JFK";
    
    @Override
    public ApiOrderResponse preProcessCreateOrder(ExpressOrderApi expressOrderApi) {
        // 州大写二字码
        String consigneeState = expressOrderApi.getConsigneeState();
        if (StringUtils.isNotBlank(consigneeState)) {
            consigneeState = StringUtils.trim(consigneeState);
            if (consigneeState.length() == 2) {
                consigneeState = consigneeState.toUpperCase();
            } else {
                Map<String, String> americaState2Code = ApiUtil.getAllAmericaState2();
                String upperCase = consigneeState.toUpperCase();
                consigneeState = americaState2Code.get(upperCase);
            }
        }
        if (StringUtils.isBlank(consigneeState)) {
            return new ApiOrderResponse(false, null, PropertiesUtil.getProperty("postpony.consignee.state.required"), null);
        }
        if (StringUtils.isBlank(expressOrderApi.getConsigneeName())) {
            return new ApiOrderResponse(false, null, PropertiesUtil.getProperty("postpony.consignee.namn.required"), null);
        }
        String consigneeTelephone = expressOrderApi.getConsigneeTelephone();
        String consigneeMobile = expressOrderApi.getConsigneeMobile();
        if (StringUtils.isEmpty(consigneeTelephone) && StringUtils.isEmpty(consigneeMobile)) {
            return new ApiOrderResponse(false, null, PropertiesUtil.getProperty("postpony.consignee.mobile.telephone.required"), null);
        }
        Map<String, String> configureMap = expressOrderApi.getApiCredentials();
        // 启用默认发件人信息
        String defaulShipper = configureMap.get(ApiCredential.POSTPONY_ENABLE_DEFAULT_SHIPPER.getKey());
        if (StringUtils.isNotBlank(defaulShipper) && ENABLE.equals(defaulShipper.trim())) {
            expressOrderApi.setShipperName(configureMap.get(ApiCredential.POSTPONY_DEFAULT_SHIPPER_NAME.getKey()));
            expressOrderApi.setShipperCompanyName(configureMap.get(ApiCredential.POSTPONY_DEFAULT_SHIPPER_COMPANYNAME.getKey()));
            expressOrderApi.setShipperTelephone(configureMap.get(ApiCredential.POSTPONY_DEFAULT_SHIPPER_TELEPHONE.getKey()));
            expressOrderApi.setShipperAddress1(configureMap.get(ApiCredential.POSTPONY_DEFAULT_SHIPPER_ADDRESS.getKey()));
            expressOrderApi.setShipperCity(configureMap.get(ApiCredential.POSTPONY_DEFAULT_SHIPPER_CITY.getKey()));
            expressOrderApi.setShipperState(configureMap.get(ApiCredential.POSTPONY_DEFAULT_SHIPPER_STATE.getKey()));
            expressOrderApi.setShipperPostCode(configureMap.get(ApiCredential.POSTPONY_DEFAULT_SHIPPER_POSTCODE.getKey()));
            expressOrderApi.setShipperCountry(configureMap.get(ApiCredential.POSTPONY_DEFAULT_SHIPPER_COUNTRY.getKey()));
        }
        // 分拣口
        String sorting = null;
        String laxPort = configureMap.get(ApiCredential.POSTPONY_LAX_STATE.getKey());
        if (StringUtils.isBlank(laxPort)) {
            laxPort = ApiCredential.POSTPONY_LAX_STATE.getValue();
        }
        String jfkPort = configureMap.get(ApiCredential.POSTPONY_JFK_STATE.getKey());
        if (StringUtils.isBlank(jfkPort)) {
            jfkPort = ApiCredential.POSTPONY_JFK_STATE.getValue();
        }
        laxPort = laxPort.toUpperCase();
        jfkPort = jfkPort.toUpperCase();
        if (laxPort.indexOf(consigneeState) > -1) {
            sorting = LAX;
        } else if (jfkPort.indexOf(consigneeState) > -1) {
            sorting = JFK;
        }
        // 拼接备注
        String skus = "";
        List<OrderInvoice> orderInvoices = expressOrderApi.getOrderInvoices();
        if (CollectionUtils.isNotEmpty(orderInvoices)) {
            OrderInvoice orderInvoice = orderInvoices.get(0);
            skus = orderInvoice.getSkuCode() + "*" + orderInvoice.getInvoicePcs();
        }
        String customerRemark = expressOrderApi.getCustomerRemark();
        StringBuffer sysRemarkBuffer = new StringBuffer();
        sysRemarkBuffer.append(expressOrderApi.getProductCode()).append(" ").append(expressOrderApi.getCustomerCode()).append(" ").append(sorting).append(skus);
        if (StringUtils.isNotBlank(customerRemark)) {
            sysRemarkBuffer.append(" ").append(customerRemark);
        }
        expressOrderApi.setCustomerRemark(sysRemarkBuffer.toString());
        return null;
    }
    
    @Override
    public String mapping(ExpressOrderApi expressOrderApi) {
        ShipRequest shipRequest = new ShipRequest();
        Map<String, String> apiCredentials = expressOrderApi.getApiCredentials();
        shipRequest.setShipType(apiCredentials.get(ApiCredential.POSTPONY_SHIPTYPE.getKey()));
        shipRequest.setAuthorizedKey(apiCredentials.get(ApiCredential.POSTPONY_AUTHORIZEDKEY.getKey()));// 企业授权码
        UserCredential userCredential = new UserCredential(apiCredentials.get(ApiCredential.POSTPONY_KEY.getKey()), apiCredentials.get(ApiCredential.POSTPONY_SECRET.getKey()));
        shipRequest.setUserCredential(userCredential);
        shipRequest.setOrderId(expressOrderApi.getCustomerInvoiceCode());// 小马的订单号 客户的参考号
        RequstInfo requstInfo = new RequstInfo();
        
        Shipper shipper = new Shipper();
        shipper.setPersonName(expressOrderApi.getShipperName());
        shipper.setCompanyName(StringUtils.isBlank(expressOrderApi.getShipperCompanyName()) ? expressOrderApi.getShipperName() : expressOrderApi.getShipperCompanyName());
        shipper.setCity(expressOrderApi.getShipperCity());
        shipper.setCountryCode(expressOrderApi.getShipperCountry());
        shipper.setCountryName(CountryUtil.getCountryNameEnByCountryCode(expressOrderApi.getShipperCountry()));
        shipper.setPostalCode(expressOrderApi.getShipperPostCode());
        shipper.setPhoneNumber(expressOrderApi.getShipperTelephone());
        shipper.setStateOrProvinceCode(expressOrderApi.getShipperState());
        List<String> shipperAddressLines = new ArrayList<String>();
        shipperAddressLines.add(expressOrderApi.getShipperAddress1());
        shipperAddressLines.add(StringUtils.isBlank(expressOrderApi.getShipperAddress2()) ? null : expressOrderApi.getShipperAddress2());
        shipper.setStreetLines(shipperAddressLines);
        requstInfo.setShipper(shipper);
        
        Recipient recipient = new Recipient();
        recipient.setPersonName(expressOrderApi.getConsigneeName());
        recipient.setCompanyName(StringUtils.isBlank(expressOrderApi.getConsigneeCompanyName()) ? expressOrderApi.getConsigneeName() : expressOrderApi.getConsigneeCompanyName());
        recipient.setCity(expressOrderApi.getConsigneeCity());
        recipient.setCountryCode(expressOrderApi.getCountryCode());
        recipient.setCountryName(CountryUtil.getCountryNameEnByCountryCode(expressOrderApi.getCountryCode()));
        recipient.setPostalCode(expressOrderApi.getConsigneePostCode());
        recipient.setPhoneNumber(expressOrderApi.getConsigneeTelephone()); // expressOrderApi.getConsigneeMobile() 小马那边 就显示了 一个 参数 写的多的 是 电话 所以这里写电话了
        recipient.setStateOrProvinceCode(expressOrderApi.getConsigneeState());
        List<String> recipientAddressLines = new ArrayList<String>();
        recipientAddressLines.add(expressOrderApi.getConsigneeAddress());
        recipient.setStreetLines(recipientAddressLines);
        requstInfo.setRecipient(recipient);
        
        Package Package = new Package();
        // 直接默认下面这三个
        Package.setContentsType("Gift");
        Package.setElectronicExportType("NoEEISED");
        Package.setFTRCode("30.37 (a)");
        Package.setInvoiceNumber(null);
        Package.setShipDate(ApiUtil.getChinaTimeZoneTime());
        Package.setShippingNotes(expressOrderApi.getCustomerRemark()); // 这个是 运单备注 会打印在面单上 需要添加很多信息 客户代码 客户参考号 分区 在外面组装了
        Package.setCustomerReference(expressOrderApi.getCustomerInvoiceCode());
        requstInfo.setPackage(Package);
        
        requstInfo.setCustomsValue(2D);
        
        List<PackageItemInfo> packageItemInfos = new ArrayList<PackageItemInfo>();
        List<OrderVolume> orderVolumes = expressOrderApi.getOrderVolumes();
        PackageItemInfo packageItemInfo = null;
        if (CollectionUtils.isEmpty(orderVolumes)) {
            packageItemInfo = new PackageItemInfo();
            packageItemInfo.setHeight(10D);
            packageItemInfo.setWeight(0.25D);
            packageItemInfo.setLength(10D);
            packageItemInfo.setWidth(10D);
            requstInfo.setCustomsValue(20D);
            packageItemInfos.add(packageItemInfo);
        } else {
            for (OrderVolume orderVolume : orderVolumes) {
                packageItemInfo = new PackageItemInfo();
                packageItemInfo.setHeight(orderVolume.getHeight());
                packageItemInfo.setWeight(orderVolume.getWeight());
                packageItemInfo.setLength(orderVolume.getLength());
                packageItemInfo.setWidth(orderVolume.getWidth());
                packageItemInfos.add(packageItemInfo);
            }
        }
        requstInfo.setPackageItems(packageItemInfos);
        
        List<CustomsItem> customsItems = new ArrayList<CustomsItem>();
        List<OrderInvoice> orderInvoices = expressOrderApi.getOrderInvoices();
        if (CollectionUtils.isNotEmpty(orderInvoices)) {
            CustomsItem customsItem = null;
            for (OrderInvoice orderInvoice : orderInvoices) {
                customsItem = new CustomsItem();
                customsItem.setCountryOfOrigin(DEFAULT_SHIPPER_COUNTRY_CODE);
                customsItem.setCustomsValue(orderInvoice.getInvoiceAmount());
                customsItem.setDescription(orderInvoice.getSkuCode() + "," + orderInvoice.getSkuNameEn());
                customsItem.setQuantity(orderInvoice.getInvoicePcs());
                customsItem.setUnitPrice(orderInvoice.getPurchasingPrice());
                customsItem.setWeight(orderInvoice.getInvoiceWeight());
                customsItems.add(customsItem);
            }
            requstInfo.setCustomsList(customsItems);
        }
        requstInfo.setLbSize("S4X6");
        shipRequest.setRequstInfo(requstInfo);
        return ApiUtil.jaxbObjectToXML(shipRequest, ShipRequest.class);
    }
    
    @Override
    public ApiOrderResponse createOrder(ExpressOrderApi expressOrderApi) {
        try {
            ApiOrderResponse apiOrderResponse = preProcessCreateOrder(expressOrderApi);
            if (null != apiOrderResponse) {
                return apiOrderResponse;
            }
            String orderXml = mapping(expressOrderApi);
            orderXml = orderXml.replace("shipRequest", "ShipRequest");
            LOGGER.info("postpony.shipment.request:{}", orderXml);
            HttpClientResult httpClientResult = HttpClientPoolUtil.doPost(ApiCredential.POSTPONY_CREATEORDER.getValue(), HttpClientPoolUtil.setXmlHeader(), orderXml);
            if (null == httpClientResult) {
                return new ApiOrderResponse(false, null, ApiOrderError.SERVICE_NO_DATA_RETURN.getMessage(), true, null);
            }
            String response = httpClientResult.getContent();
            if (StringUtils.isBlank(response)) {
                return new ApiOrderResponse(false, null, ApiOrderError.SERVICE_NO_DATA_RETURN.getMessage(), true, null);
            }
            LOGGER.info("postpony.shipment.response:{}", response);
            String result = selectNode("Sucess/", response);
            if (FAIL.equalsIgnoreCase(result)) {
                String errorMsg = selectNode("Msg/", response);
                return new ApiOrderResponse(false, null, errorMsg, response);
            }
            // 追踪号
            String MainTrackingNum = selectNode("MainTrackingNum/", response);
            // 面单数据base64
            String LableData = selectNode("LableData/base64Binary", response);
            // 面单id下载用的
            String LabelId = selectNode("LabelId/", response);
            // 面单远程地址
            String Url = selectNode("Url/", response);
            if (StringUtils.isBlank(LableData)) {
                return new ApiOrderResponse(false, null, "没有获取到面单数据", null);
            }
            String pdfName = LabelId + LabelSuffix.PDF.getSuffix();
            // 当前月份
            String centrePath = ApiUtil.getCurrentDay() + File.separator;
            String relativePath = DEFAULT_LABEL_FOLDER + File.separator + centrePath;
            String folderPath = DEFAULT_LABEL_ROOT + relativePath;
            if (!new File(folderPath).exists()) {
                new File(folderPath).mkdirs();
            }
            String fileUrl = folderPath + pdfName;
            apiOrderResponse = new ApiOrderResponse();// 回传数据
            // 写入PDF
            if (ApiUtil.decoderBase64File(LableData, fileUrl)) {
                apiOrderResponse.setLmLabelUrl(relativePath + pdfName);// 本地地址
            } else {
                try {
                    FileUtils.copyURLToFile(new URL(Url), new File(fileUrl));
                    apiOrderResponse.setLmLabelUrl(relativePath + pdfName);// 本地地址
                } catch (Exception e) {
                    LOGGER.error("postpony.copy.url.to.file.exception:{}", e);
                }
            }
            apiOrderResponse.setSuccess(true);// 成功
            apiOrderResponse.setReferenceNo(expressOrderApi.getCustomerInvoiceCode());
            apiOrderResponse.setTrackNumber(MainTrackingNum);// 追踪号
            apiOrderResponse.setThirdPartyorderNo(LabelId);// LabelId
            apiOrderResponse.setLabelUrl(Url);// 远端地址
            apiOrderResponse.setOriginalResponse(response);// 原始参数
            return apiOrderResponse;
        } catch (Exception e) {
            LOGGER.error("postpony.shipment.exception:{}", e);
            return new ApiOrderResponse(false, null, ApiOrderError.CREATE_ORDER_EXCEPTION.getMessage(), null);
        }
    }
    
    @Override
    public ApiLabelResponse label(String trackNumber, Map<String, String> configureMap) {
        return null;
    }
    
    @Override
    public ApiLabelResponse labelRender(String trackNumber, ExpressOrderApi expressOrderApi) {
        return null;
    }
    
    @Override
    public void tracking(String trackNumber, Map<String, String> configureMap) {
    }
    
    @Override
    public String trackNumber(String code, Map<String, String> configureMap) {
        return null;
    }
    
    public static String selectNode(String node, String xml) {
        try {
            Document document = DocumentHelper.parseText(xml); // 将字符串转为XML
            Element rootElement = document.getRootElement(); // 获取根节点
            // 获得当前标签下指定名称的第一个子标签
            String[] split = node.split("/");
            Element conElem = null;
            for (int i = 0; i < split.length; i++) {
                if (i == 0) {
                    conElem = rootElement.element(split[i]);
                } else {
                    conElem = conElem.element(split[i]);
                }
            }
            Object data = conElem.getData();
            return data.toString();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    
    public static void main(String[] args)
        throws Exception {
        DownloadRequest downloadRequest = new DownloadRequest();
        UserCredential userCredential = new UserCredential("5efa3eaf", "cff7e69bfc4640");
        downloadRequest.setUserCredential(userCredential);
        downloadRequest.setLabelId("16725542");
        String jaxbObjectToXML = ApiUtil.jaxbObjectToXML(downloadRequest, DownloadRequest.class);
        jaxbObjectToXML = jaxbObjectToXML.replace("downloadRequest", "DownloadRequest");// 替换大小写
        Map<String, String> headerMap = new HashMap<String, String>();
        headerMap.put("Content-type", "application/xml;charset=utf-8");
        HttpClientResult httpClientResult = HttpClientPoolUtil.doPost("https://api.postpony.com/api/Download", headerMap, jaxbObjectToXML);
        System.out.println(httpClientResult.getCode());
    }

    @Override
    public ApiLabelResponse label(String referenceNo, String trackNumber, Map<String, String> configureMap) {
        if (StringUtils.isBlank(trackNumber)) {
            return new ApiLabelResponse(trackNumber, null);
        }
        DownloadRequest downloadRequest = new DownloadRequest();
        UserCredential userCredential = new UserCredential(configureMap.get(ApiCredential.POSTPONY_KEY.getKey()), configureMap.get(ApiCredential.POSTPONY_SECRET.getKey()));
        downloadRequest.setUserCredential(userCredential);
        downloadRequest.setLabelId(referenceNo);
        String requestXml = ApiUtil.jaxbObjectToXML(downloadRequest, DownloadRequest.class);
        requestXml = requestXml.replace("downloadRequest", "DownloadRequest");// 替换大小写
        LOGGER.info("postpony.label.request:{}", requestXml);
        try {
            HttpClientResult httpClientResult = HttpClientPoolUtil.doPost(ApiCredential.POSTPONY_LABLE.getValue(), HttpClientPoolUtil.setXmlHeader(), requestXml);
            if (null == httpClientResult) {
                return new ApiLabelResponse(trackNumber, null);
            }
            String originalResponse = httpClientResult.getContent();
            String result = selectNode("Sucess/", originalResponse);
            if (FAIL.equalsIgnoreCase(result)) {
                return new ApiLabelResponse(trackNumber, null);
            }
            String LableData = selectNode("LableData/base64Binary", originalResponse);
            String pdfName = trackNumber + LabelSuffix.PDF.getSuffix();
            String centrePath = ApiUtil.getCurrentDay() + File.separator;
            String relativePath = DEFAULT_LABEL_FOLDER + File.separator + centrePath;
            String folderPath = DEFAULT_LABEL_ROOT + relativePath;
            if (!new File(folderPath).exists()) {
                new File(folderPath).mkdirs();
            }
            String fileUrl = folderPath + pdfName;
            ApiLabelResponse apiLabelResponse = new ApiLabelResponse();
            if (ApiUtil.decoderBase64File(LableData, fileUrl)) {
                apiLabelResponse.setRelativePath(relativePath + pdfName);
            }
            apiLabelResponse.setBarCode(trackNumber);
            apiLabelResponse.setLabelPath(null);
            apiLabelResponse.setLabelFormat(LabelFormat.PDF.getFormat());
            return apiLabelResponse;
        } catch (Exception e) {
            return new ApiLabelResponse();
        }
    }
}